#ifndef SEMINIX_THREAD_INFO_H
#define SEMINIX_THREAD_INFO_H

#include <seminix/bitops.h>
#include <asm/thread_info.h>
#include <asm/current.h>

#define current_thread_info() ((struct thread_info *)current)

#ifndef THREAD_ALIGN
#define THREAD_ALIGN	THREAD_SIZE
#endif

static inline void set_ti_thread_flag(struct thread_info *ti, int flag)
{
    set_bit(flag, (unsigned long *)&ti->flags);
}

static inline void clear_ti_thread_flag(struct thread_info *ti, int flag)
{
    clear_bit(flag, (unsigned long *)&ti->flags);
}

static inline void update_ti_thread_flag(struct thread_info *ti, int flag,
                     bool value)
{
    if (value)
        set_ti_thread_flag(ti, flag);
    else
        clear_ti_thread_flag(ti, flag);
}

static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag)
{
    return test_and_set_bit(flag, (unsigned long *)&ti->flags);
}

static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag)
{
    return test_and_clear_bit(flag, (unsigned long *)&ti->flags);
}

static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
{
    return test_bit(flag, (unsigned long *)&ti->flags);
}

#define set_thread_flag(flag) \
    set_ti_thread_flag(current_thread_info(), flag)
#define clear_thread_flag(flag) \
    clear_ti_thread_flag(current_thread_info(), flag)
#define update_thread_flag(flag, value) \
    update_ti_thread_flag(current_thread_info(), flag, value)
#define test_and_set_thread_flag(flag) \
    test_and_set_ti_thread_flag(current_thread_info(), flag)
#define test_and_clear_thread_flag(flag) \
    test_and_clear_ti_thread_flag(current_thread_info(), flag)
#define test_thread_flag(flag) \
    test_ti_thread_flag(current_thread_info(), flag)

#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)

extern void __compiletime_error("copy source size is too small")
__bad_copy_from(void);
extern void __compiletime_error("copy destination size is too small")
__bad_copy_to(void);

static inline void copy_overflow(int size, unsigned long count)
{
    WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
}

static __always_inline bool
check_copy_size(const void *addr, usize bytes, bool is_source)
{
    int sz = __compiletime_object_size(addr);
    if (unlikely(sz >= 0 && sz < bytes)) {
        if (!__builtin_constant_p(bytes))
            copy_overflow(sz, bytes);
        else if (is_source)
            __bad_copy_from();
        else
            __bad_copy_to();
        return false;
    }
    return true;
}

#endif /* !SEMINIX_THREAD_INFO_H */
